package org.jarx.android.reader;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.webkit.WebViewClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

public class ItemActivity extends Activity {

    public static final String INTENT_EXTRA_WHERE = "where";
    public static final String INTENT_EXTRA_WHERE_ARGS = "whereArgs";
    public static final String INTENT_EXTRA_ITEM_ID = "itemId";
    private static final int DIALOG_MARK_AS_READ = 1;

    private static final String TAG = "ItemActivity";

    private Subscription intentSub;
    private Tag intentTag;
    private boolean iconInitialized;
    private Query query;
    private Item currentItem;
    private Subscription currentSub;
    private Item.FilterCursor itemsCursor;
    private HashSet<Long> readItemIds;
    private ReaderService service;
    private boolean starred;

    // NOTE: for "omit_item_list" mode
    private boolean omitItemList;
    private boolean unreadOnly;

    private final Handler handler = new Handler();

    private final Runnable hideTouchControlViewsRunner = new Runnable() {
        public void run() {
            hideTouchControlViews();
        }
    };

    private ServiceConnection serviceConn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder binder) {
            ItemActivity.this.service = ReaderService.getService(binder);
        }
        @Override
        public void onServiceDisconnected(ComponentName className) {
            ItemActivity.this.service = null;
        }
    };

    private final Animation prevHideAnim = new AlphaAnimation(1F, 0F);
    private final Animation nextHideAnim = new AlphaAnimation(1F, 0F);
    private final Animation zoomCtrlHideAnim = new AlphaAnimation(1F, 0F);

    @Override
    public void onCreate(Bundle savedState) {
        super.onCreate(savedState);

        bindService(new Intent(this, ReaderService.class),
            this.serviceConn, Context.BIND_AUTO_CREATE);

        final Context c = getApplicationContext();
        Intent intent = getIntent();

        this.omitItemList = Prefs.isOmitItemList(this);
        if (this.omitItemList) {
            this.unreadOnly = true;
        } else {
            this.unreadOnly = intent.getBooleanExtra(
                ActivityHelper.EXTRA_UNREAD_ONLY, true);
        }

        long subId = intent.getLongExtra(ActivityHelper.EXTRA_SUB_ID, 0);
        if (subId > 0) {
            this.intentSub = ReaderManager.getSubBy(c, Subscription._ID,
                String.valueOf(subId));
        } else {
            String tagUid = intent.getStringExtra(ActivityHelper.EXTRA_TAG_UID);
            if (tagUid != null) {
                this.intentTag = ReaderManager.getTagBy(c, Tag._UID, tagUid);
                if (this.intentTag != null) {
                    if (this.intentTag.getType() != Tag.TYPE_FOLDER) {
                        this.unreadOnly = false;
                    }
                }
            }
        }

        this.query = ActivityHelper.getItemQuery(this.intentSub, this.intentTag,
            this.unreadOnly);
        this.query.setSelection(Item.SELECT_ID);

        long itemId = intent.getLongExtra(INTENT_EXTRA_ITEM_ID, 0);
        if (savedState != null) {
            itemId = savedState.getLong("itemId", 0);
            long[] ids = savedState.getLongArray("readItemIds");
            if (ids != null) {
                this.readItemIds = new HashSet<Long>(ids.length * 2);
                for (long id: ids) {
                    this.readItemIds.add(id);
                }
            }
        }
        if (this.readItemIds == null) {
            this.readItemIds = new HashSet<Long>(32);
        }

        setContentView(R.layout.item);
        ActivityHelper.bindTitle(this);

        final WebView bodyView = (WebView) findViewById(R.id.item_body);
        bodyView.setOnTouchListener(new BodyWebViewTouchListener());
        bodyView.setWebViewClient(new BodyWebViewClient());
        final WebSettings settings = bodyView.getSettings();
        settings.setJavaScriptEnabled(false);
        settings.setBuiltInZoomControls(false);
        settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);

        final View previous = findViewById(R.id.previous);
        previous.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                previousItem();
            }
        });
        final View next = findViewById(R.id.next);
        next.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                nextItem();
            }
        });
        final View zoomIn = findViewById(R.id.zoom_in);
        zoomIn.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                bodyView.zoomIn();
            }
        });
        final View zoomOut = findViewById(R.id.zoom_out);
        zoomOut.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                bodyView.zoomOut();
            }
        });

        final View star = findViewById(R.id.icon_star);
        star.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                toggleStar(null);
            }
        });

        initItems(itemId);
    }

    @Override
    public void onResume() {
        super.onResume();
        final WebView bodyView = (WebView) findViewById(R.id.item_body);
        WebSettings settings = bodyView.getSettings();
        settings.setDefaultFontSize(Prefs.getItemBodyFontSize(
            getApplicationContext()));
    }

    @Override
    public void onPause() {
        super.onPause();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        destroyItems();
        unbindService(this.serviceConn);
    }

    @Override
    protected Dialog onCreateDialog(int id) {
        switch (id) {
        case DIALOG_MARK_AS_READ:
            return new AlertDialog.Builder(this)
                .setTitle(R.string.txt_reads)
                .setMessage(R.string.msg_confirm_mark_as_read)
                .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int whichButton) {
                        progressMarkAsRead();
                    }
                })
                .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int whichButton) {
                    }
                }).create();
        }
        return null;
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        long[] ids = new long[this.readItemIds.size()];
        int i = 0;
        for (long id: this.readItemIds) {
            ids[i++] = id;
        }
        outState.putLongArray("readItemIds", ids);
        if (this.currentItem != null) {
            outState.putLong("itemId", this.currentItem.getId());
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.item, menu);
        MenuItem starMenu = menu.findItem(R.id.menu_star);
        if (this.starred) {
            starMenu.setTitle("Remove star");
        } else {
            starMenu.setTitle("Add star");
        }
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem menuItem) {
        switch (menuItem.getItemId()) {
        case R.id.menu_star:
            toggleStar(menuItem);
            return true;
        case R.id.menu_mark_as_read:
            showDialog(DIALOG_MARK_AS_READ);
            return true;
        case R.id.menu_prefs:
            startActivityForResult(new Intent(this, PrefActivity.class),
                ActivityHelper.REQUEST_PREFS);
            return true;
        }
        return false;
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == ActivityHelper.REQUEST_PREFS) {
            if (this.currentItem == null) {
                initItems(0);
            } else {
                initItems(this.currentItem.getId());
            }
        }
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_SEARCH) {
            // NOTE: ignore search
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

    private void progressMarkAsRead() {
        if (this.service == null) {
            return;
        }
        final ReaderManager rman = this.service.getSharedReaderManager();
        if (rman == null) {
            return;
        }
        final Context c = getApplicationContext();
        final Subscription sub = this.intentSub;

        final Tag tag = this.intentTag;
        final long time = System.currentTimeMillis();
        final ProgressDialog dialog = new ProgressDialog(this);
        dialog.setIndeterminate(true);
        dialog.setMessage(getText(R.string.msg_mark_as_read_running));
        dialog.show();
        new Thread() {
            public void run() {
                try {
                    if (sub != null) {
                        rman.syncMarkAllAsRead(sub, time);
                    } else if (tag != null) {
                        rman.syncMarkAllAsRead(tag, time);
                    } else {
                        rman.syncMarkAllAsRead(time);
                    }
                } catch (IOException e) {
                    ActivityHelper.showToast(c, e);
                } catch (ReaderException e) {
                    ActivityHelper.showToast(c, e);
                }
                handler.post(new Runnable() {
                    public void run() {
                        if (sub != null) {
                            ItemActivity.this.intentSub = rman.getSubById(
                                sub.getId());
                        }
                        if (tag != null) {
                            ItemActivity.this.intentTag = rman.getTagByUid(
                                tag.getUid());
                        }
                        initItems(ItemActivity.this.currentItem.getId());
                        dialog.dismiss();
                    }
                });
            }
        }.start();
    }

    private void setCurrentItem(long itemId) {
        Context c = getApplicationContext();
        Uri uri = ContentUris.withAppendedId(Item.CONTENT_URI, itemId);
        this.currentItem = ReaderManager.getItemBy(c, uri);
        if (this.currentItem == null) {
            this.currentSub = null;
            return;
        }

        long subId = this.currentItem.getSubId();
        if (this.currentSub == null || this.currentSub.getId() != subId) {
            this.currentSub = ReaderManager.getSubBy(
                c, Subscription._ID, String.valueOf(subId));
            if (this.currentSub == null) {
                this.currentItem = null;
                return;
            }
        }

        setResult(RESULT_OK, new Intent()
            .putExtra(ActivityHelper.EXTRA_ITEM_ID, itemId));

        bindSubTitleView();
        bindItemView();
    }

    private void initItems(long itemId) {
        if (this.itemsCursor != null) {
            this.itemsCursor.close();
            this.itemsCursor = null;
        }

        Item.FilterCursor csr = new Item.FilterCursor(
            this.query.managedQuery(this));
        int count = (csr == null) ? 0: csr.getCount();
        if (count == 0 && this.unreadOnly) {
            if (csr != null) {
                csr.close();
            }
            this.unreadOnly = false;
            this.query = ActivityHelper.getItemQuery(this.intentSub, this.intentTag,
                this.unreadOnly);
            csr = new Item.FilterCursor(this.query.managedQuery(this));
            count = (csr == null) ? 0: csr.getCount();
        }

        if (count == 0) {
            if (csr != null) {
                csr.close();
            }
            bindSubTitleView();
            bindItemView();
            return;
        }

        this.itemsCursor = ActivityHelper.moveToItemId(csr, itemId);
        setCurrentItem(csr.getId());
    }

    private void destroyItems() {
        if (this.itemsCursor != null) {
            this.itemsCursor.close();
            this.itemsCursor = null;
        }
        Set<Long> ids = this.readItemIds;
        if (ids.size() == 0) {
            return;
        }

        boolean withoutCur = (!isFinishing() && this.currentItem != null);
        if (withoutCur) {
            ids.remove(this.currentItem.getId());
        }
        long[] itemIds = new long[ids.size()];
        int i = 0;
        for (long id: ids) {
            itemIds[i++] = id;
        }
        ids.clear();
        if (withoutCur) {
            ids.add(this.currentItem.getId());
        }

        Intent intent = new Intent(ReaderService.ACTION_READ);
        intent.putExtra("itemIds", itemIds);
        sendBroadcast(intent);
    }

    private void nextItem() {
        scheduleHideTouchControlViews();
        if (this.itemsCursor != null && this.itemsCursor.moveToNext()) {
            setCurrentItem(this.itemsCursor.getId());
        }
    }

    private void previousItem() {
        scheduleHideTouchControlViews();
        if (this.itemsCursor != null && this.itemsCursor.moveToPrevious()) {
            setCurrentItem(this.itemsCursor.getId());
        }
    }

    private void bindTouchControlViews(boolean visible) {
        if (Prefs.isShowItemControlls(
                getApplicationContext())) {
            visible = true;
        }

        boolean hasPrevious = false;
        boolean hasNext = false;
        if (this.itemsCursor != null) {
            hasPrevious = !this.itemsCursor.isFirst();
            hasNext = !this.itemsCursor.isLast();
        }

        final View previous = findViewById(R.id.previous);
        final View next = findViewById(R.id.next);
        final View zoomControlls = findViewById(R.id.zoom_controlls);

        boolean previousVisible = (previous.getVisibility() == View.VISIBLE);
        boolean nextVisible = (next.getVisibility() == View.VISIBLE);

        if (hasPrevious && visible && !previousVisible) {
            previous.setVisibility(View.VISIBLE);
        } else if (!hasPrevious && previousVisible) {
            previous.setVisibility(View.INVISIBLE);
        }

        if (hasNext && visible && !nextVisible) {
            next.setVisibility(View.VISIBLE);
        } else if (!hasNext && nextVisible) {
            next.setVisibility(View.INVISIBLE);
        }

        if (zoomControlls.getVisibility() != View.VISIBLE) {
            zoomControlls.setVisibility(View.VISIBLE);
        }
    }

    private void hideTouchControlViews() {
        if (Prefs.isShowItemControlls(
                getApplicationContext())) {
            return;
        }

        final View previous = findViewById(R.id.previous);
        final View next = findViewById(R.id.next);
        final View zoomControlls = findViewById(R.id.zoom_controlls);

        if (previous.getVisibility() == View.VISIBLE) {
            Animation a = this.prevHideAnim;
            a.setDuration(500);
            previous.startAnimation(a);
            previous.setVisibility(View.INVISIBLE);
        }

        if (next.getVisibility() == View.VISIBLE) {
            Animation a = this.nextHideAnim;
            a.setDuration(500);
            next.startAnimation(a);
            next.setVisibility(View.INVISIBLE);
        }

        if (zoomControlls.getVisibility() == View.VISIBLE) {
            Animation a = this.zoomCtrlHideAnim;
            a.setDuration(500);
            zoomControlls.startAnimation(a);
            zoomControlls.setVisibility(View.INVISIBLE);
        }
    }

    private void scheduleHideTouchControlViews() {
        this.handler.removeCallbacks(hideTouchControlViewsRunner);
        this.handler.postDelayed(hideTouchControlViewsRunner, 2000);
    }

    private void bindSubTitleView() {
        Context c = getApplicationContext();
        TextView subTitleView = (TextView) findViewById(R.id.sub_title);
        ImageView iconView = (ImageView) findViewById(R.id.sub_icon);

        StringBuilder buff = new StringBuilder(128);
        if (this.intentSub != null) {
            Subscription sub = this.intentSub;
            buff.append(ActivityHelper.toLabelWithUnread(sub));
            if (!this.iconInitialized) {
                Bitmap icon = sub.getIcon(this);
                if (icon == null) {
                    iconView.setImageResource(R.drawable.item_read);
                } else {
                    iconView.setImageBitmap(icon);
                }
                this.iconInitialized = true;
            }
        } else if (this.intentTag != null) {
            Tag tag = this.intentTag;
            buff.append(ActivityHelper.toLabelWithUnread(tag, this));
            switch (tag.getType()) {
            case Tag.TYPE_TAG_STARRED:
                if (!this.iconInitialized) {
                    iconView.setImageResource(R.drawable.star);
                    this.iconInitialized = true;
                }
                break;
            case Tag.TYPE_TAG_LABEL:
                if (!this.iconInitialized) {
                    iconView.setImageResource(R.drawable.tag);
                    this.iconInitialized = true;
                }
                break;
            case Tag.TYPE_FOLDER:
                if (!this.iconInitialized) {
                    iconView.setImageResource(R.drawable.folder_open);
                    this.iconInitialized = true;
                }
                break;
            }
        } else {
            buff.append(ActivityHelper.toLabelWithUnread(
                getText(R.string.txt_all), Prefs.getUnreadCount(c)));
        }

        if (this.itemsCursor != null) {
            buff.append(" [");
            if (this.unreadOnly) {
                buff.append(getText(R.string.txt_unreads));
                buff.append(":");
            } else if (this.omitItemList) {
                buff.append(getText(R.string.txt_reads));
                buff.append(":");
            }
            buff.append(this.itemsCursor.getPosition() + 1);
            buff.append("/");
            buff.append(this.itemsCursor.getCount());
            buff.append("]");
        }

        subTitleView.setText(buff);
    }

    private void bindItemView() {
        this.starred = false;
        Context c = getApplicationContext();
        ImageView readUnreadView = (ImageView) findViewById(R.id.icon_read_unread);
        ImageView starView = (ImageView) findViewById(R.id.icon_star);
        TextView titleView = (TextView) findViewById(R.id.item_title);
        WebView bodyView = (WebView) findViewById(R.id.item_body);

        Item item = this.currentItem;
        if (item == null) {
            titleView.setText(getText(R.string.msg_no_item_for_title));
            bodyView.clearView();
            return;
        }

        readUnreadView.setImageResource(item.isRead()
            ? R.drawable.item_read: R.drawable.item_unread);

        this.starred = ReaderManager.isStarred(c, item.getId());
        starView.setImageResource(this.starred
            ? android.R.drawable.btn_star_big_on
            : android.R.drawable.btn_star_big_off);

        if (this.intentSub == null && this.currentSub != null) {
            StringBuilder buff = new StringBuilder(64);
            buff.append(item.getTitle());
            buff.append(" - ");
            buff.append(this.currentSub.getTitle());
            titleView.setText(buff);
        } else {
            titleView.setText(item.getTitle());
        }

        bodyView.loadDataWithBaseURL(GoogleReaderClient.URL_BASE_ + "/",
            createBodyHtml(item), "text/html", "UTF-8", "about:blank");

        if (Prefs.isShowItemControlls(getApplicationContext())) {
            bindTouchControlViews(true);
        }
        if (!item.isRead()) {
            this.readItemIds.add(item.getId());
        }
    }

    private static String createBodyHtml(Item item) {
        String body = item.getContent();
        if (body == null) {
            body = "";
        }
        long time = item.getPublishedTime();
        String author = item.getAuthor();
        StringBuilder buff = new StringBuilder(body.length() + 256);
        buff.append("<div class=\"item_info\">");
        buff.append("<a href=\"");
        buff.append(item.getLink());
        buff.append("\">Permalink</a>");
        if (time > 0 || (author != null && author.length() > 0)) {
            buff.append(" |");
            if (time > 0) {
                buff.append(" <small class=\"rel\">");
                buff.append(Utils.formatTimeAgo(time));
                buff.append("</small>");
            }
            if (author != null && author.length() > 0) {
                buff.append(" <small class=\"author\">by ");
                buff.append(Utils.htmlEscape(item.getAuthor()));
                buff.append("</small>");
            }
        }
        buff.append("</div>");
        buff.append("<div class=\"item_body\" style=\"margin:8px 0 50px 0; word-wrap:break-word; overflow:auto;\">");
        buff.append(body);
        buff.append("</div>");
        return new String(buff);
    }

    private void toggleStar(MenuItem starMenu) {
        if (this.service == null || this.currentItem == null) {
            return;
        }
        this.starred = !this.starred;

        ImageView starView = (ImageView) findViewById(R.id.icon_star);
        ReaderManager rman = this.service.getSharedReaderManager();
        rman.editItemStar(this.currentItem, this.starred);
        if (this.starred) {
            starView.setImageResource(android.R.drawable.btn_star_big_on);
            if (starMenu != null) {
                starMenu.setTitle("Remove star");
            }
        } else {
            starView.setImageResource(android.R.drawable.btn_star_big_off);
            if (starMenu != null) {
                starMenu.setTitle("Add star");
            }
        }
    }

    private class BodyWebViewTouchListener implements View.OnTouchListener {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                bindTouchControlViews(true);
                break;
            case MotionEvent.ACTION_UP:
                scheduleHideTouchControlViews();
                break;
            case MotionEvent.ACTION_MOVE:
                break;
            }
            return false;
        }
    }

    private class BodyWebViewClient extends WebViewClient {

        @Override
        public boolean shouldOverrideUrlLoading(WebView view, final String url) {
            if (Prefs.isDisableItemLinks(getApplicationContext())) {
                return true;
            }
            new AlertDialog.Builder(ItemActivity.this)
                .setTitle(R.string.msg_confirm_browse)
                .setMessage(url)
                .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int whichButton) {
                        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                        startActivity(intent);
                    }
                })
                .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int whichButton) {
                    }
                }).show();
            return true;
        }
    }
}
